//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file types.h
  * @brief The types
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGUTTARUIS__TYPES__H_
#define __SAGUTTARUIS__TYPES__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/parser/parserNodes.h"
#include "sagittarius/parallel/multisema.h"
#include "sagittarius/lexer/lexcore.h"
#include "sagittarius/symtab/symtab.h"

#ifdef __cplusplus
    #include <complex>
#endif

#ifdef __cplusplus
extern "C" {
#endif

struct __sg_type;

typedef struct {
    symcode s;
} ttran_cue;

#define SG_CMP_TTRAN_CUE(a,b) (a.s == b.s)

//-- Types --

typedef struct __sg_fieldtab_val sg_fieldtab_val;

typedef struct __sg_type_dtable_val sg_type_dtable_val;

#define SG_HC_PARAMS  struct __sg_type* t; /* type */ \
                        sg_fieldtab_val* f; /* fields */ \
                        sg_type_dtable_val* dt; /* ttable */ \
                        symcode s; /* symbol (if avail) */ \
                        uint64 o; /* OBS number of fields */

typedef struct __sg_hc {
    SG_HC_PARAMS
    // TODO: ttable
} sg_hc;

#define SG_TYPE_PARAMS  struct __sg_type* t; /* type */ \
                        symcode s; /* symbol (if avail) */ \
                        uint64 sz; /* size of base (i.e. excluding extra fields) value in bytes */

typedef struct __sg_type {
    SG_TYPE_PARAMS
    // TODO: ttable
} sg_type;

typedef struct __sg_ref_type {
    SG_TYPE_PARAMS
} sg_ref_type;

typedef struct {
    SG_TYPE_PARAMS
} sg_type_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_int_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_real_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_complex_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_str_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_fun_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_mir_tp;

/// A name used to refer to an object
typedef struct {
    SG_TYPE_PARAMS
} sg_name_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_symbol_inst_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_fctx_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_fieldrec_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_fieldtab_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_type_dtran_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_type_dtable_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_list_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_list_iter_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_locals_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_node_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_reaction_rule_tp;

typedef struct {
    SG_TYPE_PARAMS
} sg_network_tp;

//-- Values --

typedef struct __sg_value sg_value;

//FIXME: change data to sg_name_val array for uniformity; sacrificing the extra space is worth it

#define SG_VAL_PARAMS   sg_type* t; /* type */ \
                        uint64 r; /* refcount */ \
                        sg_hc* hc; /* hidden class */ \
                        sg_value** p; /* data */ \

typedef struct __sg_value {
    SG_VAL_PARAMS
} sg_value;

typedef struct {
    SG_VAL_PARAMS
    // OBS: use p as sg_value**
    sg_value** v;
} sg_ref_value;

/// A value that represents a type (so types can be compared, etc.)
typedef struct {
    SG_VAL_PARAMS
    /// Type indicated
    sg_type* tp;
} sg_type_val;

typedef struct {
    SG_VAL_PARAMS
    /// Integral value
    int64 v;
} sg_int_val;

typedef struct {
    SG_VAL_PARAMS
    /// Real value
    CReal v;
} sg_real_val;

#ifdef __cplusplus
    
    typedef struct {
        SG_VAL_PARAMS
        /// Complex value
        std::complex<CReal> v;
    } sg_complex_val;
    
#endif

typedef struct {
    SG_VAL_PARAMS
    /// Buffer
    constLexBuf w;
    /// Length
    uint64 n;
} sg_str_val;

#define SG_FUN_VAL_F_OFFSET 3

typedef struct {
    SG_VAL_PARAMS
    /// Num args
    uint64 nargs;
    /// 1 if function returns void, zero otherwise
    uint64 vd;
    /// Function symbol, if available
    symcode s;
    /// C fun ptr
    void* f;
    /// LLVM fun ptr
    void* lf;
    /// LLVM fun ptr
    void* lpf;
    /// LLVM fun type
    void* lft;
} sg_fun_val;

/// Grav lens
typedef struct {
    SG_VAL_PARAMS
    /// Object to create the field in
    sg_value* o;
    /// Symbol to be created (or not)
    symcode s;
} sg_mir_val;

/// Symbol instance
typedef struct {
    SG_VAL_PARAMS
    /// Symbol (the name)
    symcode s;
    /// Object
    sg_value* o;
    /// LLVM value representing obj ptr
    void* lxp;
} sg_symbol_inst;

#define SG_SYMBOL_INST_SYM_OFF 0
#define SG_SYMBOL_INST_OBJ_OFF 1

typedef enum {
    SG_SYMTP_NORMAL,
    SG_SYMTP_SPECIES,
    SG_SYMTP_RATE_LAW_CONST
} sg_symbol_type;

typedef struct __sg_fctx_val sg_fctx_val;

typedef struct {
    SG_VAL_PARAMS
    /// Symbol (the name)
    symcode s;
    /// Object
    sg_value* o;
    /// LLVM value representing symbol instance (sg_symbol_inst)
    void* syminst;
    /// Position in local lineup
    uint64 pos;
    /// Context in which this symbol is defined
    sg_fctx_val* ctx;
    /// Symbol type
    sg_symbol_type sym_tp;
} sg_name_val;

//typedef struct __sg_session sg_session;

// TODO: remane to local_ctx_val or something
typedef struct __sg_fctx_val {
    SG_VAL_PARAMS
    /// session
    struct __sg_session* ses;
    /// num
    uint64 n;
    /// cap
    uint64 c;
    /// buf
    sg_name_val** m;
    /// Parent context
    struct __sg_fctx_val* par;
    /// LLVM StructType
    void* ls_locals;
    /// LLVM value for the locals of this context
    //void* vlocals;
    void* vlocals2;
} sg_fctx_val;

typedef struct {
    SG_VAL_PARAMS
    ///Symbol
    symcode s;
    /// Data size
    uint64 k;
    /// Static object
    sg_value* v;
} sg_fieldrec_val;

typedef struct __sg_fieldtab_val {
    SG_VAL_PARAMS
    /// Size (in bytes)
    uint64 k;
    /// Num fields
    uint64 n;
    /// Field capacity
    uint64 c;
    /// Fields
    sg_fieldrec_val** f;
} sg_fieldtab_val;

typedef struct {
    SG_VAL_PARAMS
    /// Symbol (the name)
    symcode s;
    /// Offset
    uint64 o;
    /// Dest type
    sg_hc* dst;
} sg_type_dtran_val;

typedef struct __sg_type_dtable_val {
    SG_VAL_PARAMS
    /// Num
    uint64 n;
    /// Cap
    uint64 c;
    /// Link number
    uint64 m;
    /// Trans
    sg_type_dtran_val** tt;
} sg_type_dtable_val;

typedef struct {
    SG_VAL_PARAMS
    /// Num
    uint64 n;
    /// Cap
    uint64 c;
    /// Objects
    sg_value** v;
} sg_list_val;

typedef struct {
    SG_VAL_PARAMS
    /// List
    sg_list_val* list;
    /// Index
    uint64 n;
} sg_list_iter_val;

typedef struct __sg_locals_val {
    SG_VAL_PARAMS
    /// Parent
    struct __sg_locals_val* par;
    /// Local vars
    sg_list_val* vars;
} sg_locals_val;

typedef struct __sg_node_val sg_node_val;

typedef struct __sg_node_val {
    SG_VAL_PARAMS
    /// Child 1
    sg_node_val* a;
    /// Child 2
    sg_node_val* b;
    /// Name
    sg_name_val* name;
    /// Type
    parserExpType type;
    /// Object
    sg_value* obj;
    /// Symbol
    symcode s;
} sg_node_val;

typedef struct {
    SG_VAL_PARAMS
    /// Reaction
    sg_node_val* rxn;
    /// Rate law
    sg_node_val* rate;
} sg_reaction_rule_val;

typedef struct {
    SG_VAL_PARAMS
    /// Reaction rules
    sg_list_val* rules;
} sg_network_val;

#ifdef __cplusplus
}//extern "C"
#endif

#endif
